#ifndef DATACENTER_H
#define DATACENTER_H

#include "data.h"
#include <QWidget>

#include "../network/netclient.h"

namespace model
{

class DataCenter : public QObject
{
    Q_OBJECT

  public:
    static DataCenter *getInstance();
    ~DataCenter();

  private:
    DataCenter();
    static DataCenter *instance;

    // 列出 DataCenter 中要组织管理的所有的数据

    // 当前客户端登录到服务器对应的登录会话 id
    QString loginSessionId = "";

    // 当前的用户信息
    UserInfo *myself = nullptr;

    // 好友列表
    QList<UserInfo> *friendList = nullptr;

    // 会话列表
    QList<ChatSessionInfo> *chatSessionList = nullptr;
    // 记录当前选中的会话是哪个
    QString currentChatSessionId = "";
    // 记录每个会话中, 都有哪些成员(主要针对群聊). key 为 chatSessionId, value
    // 为成员列表
    QHash<QString, QList<UserInfo>> *memberList = nullptr;

    // 待处理的好友申请列表
    QList<UserInfo> *applyList = nullptr;

    // 每个会话的最近消息列表, key 为 chatSessionId, value 为消息列表
    QHash<QString, QList<Message>> *recentMessages = nullptr;

    // 存储每个会话, 未读消息的个数. key 为 chatSessionId, value
    // 为未读消息的个数.
    QHash<QString, int> *unreadMessageCount = nullptr;

    // 用户的好友搜索结果.
    QList<UserInfo> *searchUserResult = nullptr;

    // 历史消息搜索结果.
    QList<Message> *searchMessageResult = nullptr;

    // 短信验证码的验证 id
    QString currentVerifyCodeId = "";

    // 让 DataCenter 持有 NetClient 实例.
    network::NetClient netClient;

  public:
    // 初始化数据文件
    void initDataFile();
    // 存储数据到文件中
    void saveDataFile();
    // 从数据文件中加载数据到内存
    void loadDataFile();
    // 清空未读消息数目
    void clearUnread( const QString &chatSessionId );
    // 增加未读消息数目
    void addUnread( const QString &chatSessionId );
    // 获取未读消息数目
    int getUnread( const QString &chatSessionId );

    // 获取到当前的登录会话id
    const QString &getLoginSessionId() const
    {
        return loginSessionId;
    }

    // 验证网络连通性
    void ping()
    {
        netClient.ping();
    }

    // 针对 netclient 中的 websocket 进行初始化.
    void initWebsocket();
    // [联调修改]
    void closeWebsocket();

    //////////////////////////////////////////////////////
    /// 核心函数
    //////////////////////////////////////////////////////

    // 通过网络获取到用户的个人信息, 该函数是一个 "异步" 的函数, 只负责把 HTTP
    // 请求发出去就不管了.
    void getMyselfAsync();
    UserInfo *getMyself();
    void resetMyself( std::shared_ptr<ken_im::GetUserInfoRsp> resp );

    // 获取好友列表
    void getFriendListAsync();
    QList<UserInfo> *getFriendList();
    void resetFriendList( std::shared_ptr<ken_im::GetFriendListRsp> resp );

    // 获取会话列表
    void getChatSessionListAsync();
    QList<ChatSessionInfo> *getChatSessionList();
    void
    resetChatSessionList( std::shared_ptr<ken_im::GetChatSessionListRsp> resp );

    // 获取好友申请列表
    void getApplyListAsync();
    QList<UserInfo> *getApplyList();
    void resetApplyList(
        std::shared_ptr<ken_im::GetPendingFriendEventListRsp> resp );

    // 获取最近消息列表
    void getRecentMessageListAsync( const QString &chatSessionId,
                                    bool updateUI );
    QList<Message> *getRecentMessageList( const QString &chatSessionId );
    void
    resetRecentMessageList( const QString &chatSessionId,
                            std::shared_ptr<ken_im::GetRecentMsgRsp> resp );

    // 发送消息给服务器
    void sendTextMessageAsync( const QString &chatSessionId,
                               const QString &content );
    void sendImageMessageAsync( const QString &chatSessionId,
                                const QByteArray &content );
    void sendFileMessageAsync( const QString &chatSessionId,
                               const QString &fileName,
                               const QByteArray &content );
    void sendSpeechMessageAsync( const QString &chatSessionid,
                                 const QByteArray &content );

    // 修改用户昵称
    void changeNicknameAsync( const QString &nickname );
    void resetNickname( const QString &nickname );

    // 修改用户签名
    void changeDescriptionAsync( const QString &desc );
    void resetDescription( const QString &desc );

    // 获取短信验证码
    void getVerifyCodeAsync( const QString &phone );
    void resetVerifyCodeId( const QString &verifyCodeId );
    // 获取 verifyCodeId
    const QString &getVerifyCodeId();

    // 修改手机号码
    void changePhoneAsync( const QString &phone, const QString &verifyCodeId,
                           const QString &verifyCode );
    void resetPhone( const QString &phone );

    // 修改头像
    void changeAvatarAsync( const QByteArray &imageBytes );
    void resetAvatar( const QByteArray &avatar );

    // 删除好友
    void deleteFriendAsync( const QString &userId );
    void removeFriend( const QString &userId );

    // 发送好友申请
    void addFriendApplyAsync( const QString &userId );

    // 发送同意好友申请操作
    void acceptFriendApplyAsync( const QString &userId );
    UserInfo removeFromApplyList( const QString &userId );

    // 拒绝好友申请操作
    void rejectFriendApplyAsync( const QString &userId );

    // 创建群聊
    void createGroupChatSessionAsync( const QList<QString> &userIdList );

    // 获取会话的成员列表
    void getMemberListAsync( const QString &chatSessionId );
    QList<UserInfo> *getMemberList( const QString &chatSessionId );
    void resetMemberList( const QString &chatSessionId,
                          const QList<ken_im::UserInfo> &memberList );

    // 搜索用户
    void searchUserAsync( const QString &searchKey );
    QList<UserInfo> *getSearchUserResult();
    void resetSearchUserResult( const QList<ken_im::UserInfo> &userList );

    // 搜索历史消息
    void searchMessageAsync( const QString &searchKey );
    void searchMessageByTimeAsync( const QDateTime &begTime,
                                   const QDateTime &endTime );
    QList<Message> *getSearchMessageResult();
    void resetSearchMessageResult( const QList<ken_im::MessageInfo> &msgList );

    // 登录注册
    void userLoginAsync( const QString &username, const QString &password );
    void resetLoginSessionId( const QString &loginSessionId );
    void userRegisterAsync( const QString &username, const QString &password );
    void phoneLoginAsync( const QString &phone, const QString &verifyCode );
    void phoneRegisterAsync( const QString &phone, const QString &verifyCode );

    // 获取单个文件
    void getSingleFileAsync( const QString &fileId );

    // 语音转文字
    void speechConvertTextAsync( const QString &fileId,
                                 const QByteArray &content );

    //////////////////////////////////////////////////////////////////
    /// 辅助函数
    //////////////////////////////////////////////////////////////////

    // 根据会话 id 查询会话信息
    ChatSessionInfo *findChatSessionById( const QString &chatSessionId );
    // 根据用户 id 查询会话信息
    ChatSessionInfo *findChatSessionByUserId( const QString &userId );
    // 把指定的会话信息, 放到列表头部.
    void topChatSessionInfo( const ChatSessionInfo &chatSessionInfo );
    // 根据用户 id 查询好友信息
    UserInfo *findFriendById( const QString &userId );

    // 设置/获取当前选中的会话
    void setCurrentChatSessionId( const QString &chatSessionId );
    const QString &getCurrentChatSessionId();

    // 添加消息到 DataCenter 中
    void addMessage( const Message &message );

  signals:
    // 自定义信号
    void getMyselfDone();
    void getFriendListDone();
    void getChatSessionListDone();
    void getApplyListDone();
    void getRecentMessageListDone( const QString &chatSessionId );
    void getRecentMessageListDoneNoUI( const QString &chatSessionId );
    void sendMessageDone( MessageType messageType, const QByteArray &content,
                          const QString &extraInfo );
    void updateLastMessage( const QString &chatSessionId );
    void receiveMessageDone( const Message &lastMessage );
    void changeNicknameDone();
    void changeDescriptionDone();
    void getVerifyCodeDone();
    void changePhoneDone();
    void changeAvatarDone();
    void deleteFriendDone();
    void clearCurrentSession();
    void addFriendApplyDone();
    void receiveFriendApplyDone();
    void acceptFriendApplyDone();
    void rejectFriendApplyDone();
    void receiveFriendProcessDone( const QString &nickname, bool agree );
    void createGroupChatSessionDone();
    void receiveSessionCreateDone();
    void getMemberListDone( const QString &chatSessionId );
    void searchUserDone();
    void searchMessageDone();
    void userLoginDone( bool ok, const QString &reason );
    void userRegisterDone( bool ok, const QString &reason );
    void phoneLoginDone( bool ok, const QString &reason );
    void phoneRegisterDone( bool ok, const QString &reason );
    void getSingleFileDone( const QString &fileId,
                            const QByteArray &fileContent );
    void speechConvertTextDone( const QString &fileId, const QString &text );
};

} // namespace model

#endif // DATACENTER_H
